home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / proc / procServer.c < prev    next >
C/C++ Source or Header  |  1991-05-06  |  15KB  |  526 lines

  1. /* 
  2.  *  procServer.c --
  3.  *
  4.  *    Routines to manage pool of server processes.
  5.  *
  6.  * Copyright 1987, 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/kernel/proc/RCS/procServer.c,v 9.7 91/05/06 14:36:44 kupfer Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include <sprite.h>
  21. #include <mach.h>
  22. #include <proc.h>
  23. #include <procInt.h>
  24. #include <sync.h>
  25. #include <sched.h>
  26. #include <timer.h>
  27. #include <list.h>
  28. #include <vm.h>
  29. #include <fs.h>
  30. #include <fscache.h>
  31. #include <sys.h>
  32. #include <string.h>
  33. #include <status.h>
  34. #include <stdlib.h>
  35. #include <procServer.h>
  36. #include <stdio.h>
  37.  
  38. /*
  39.  * Circular queue of pending function calls.
  40.  */
  41. QueueElement    queue[NUM_QUEUE_ELEMENTS];
  42.  
  43. /*
  44.  * Indices into circular queue.  frontIndex is index of next function to call.
  45.  * nextIndex is index of where to put next call.  When frontIndex and nextIndex
  46.  * are equal then queue is full.  When frontIndex = -1 then queue is empty.
  47.  */
  48. int    frontIndex = -1;
  49. int    nextIndex = 0;
  50.  
  51. ServerInfo    *serverInfoTable;
  52.  
  53. int    proc_NumServers = PROC_NUM_SERVER_PROCS;
  54.  
  55. /* 
  56.  * Mutex to synchronize accesses to the queue of pending requests and
  57.  * to the process state.
  58.  */
  59. Sync_Semaphore    serverMutex; 
  60.  
  61. static void     ScheduleFunc _ARGS_((void (*func)(ClientData clientData,
  62.                           Proc_CallInfo    *callInfoPtr),
  63.             ClientData clientData, unsigned int interval, 
  64.             FuncInfo *funcInfoPtr));
  65. static void     CallFuncFromTimer _ARGS_((Timer_Ticks time, 
  66.             ClientData data));
  67. static void    CallFunc _ARGS_((FuncInfo *funcInfoPtr));    
  68.  
  69. /*
  70.  *----------------------------------------------------------------------
  71.  *
  72.  * Proc_CallFunc --
  73.  *
  74.  *    Start a process that calls the given function.  The process will
  75.  *    be started after waiting for interval amount of time where interval is
  76.  *    of the form expected by the timer module (e.g. timer_IntOneSecond). 
  77.  *    Proc_CallFunc can be called with interrupts disabled as long as
  78.  *    interval is 0 (when interval is non-zero, the memory allocator is
  79.  *    called).  When func is called it will be called as 
  80.  *
  81.  *        void
  82.  *        func(clientData, callInfoPtr)
  83.  *            ClientData    clientData;
  84.  *            Proc_CallInfo    *callInfoPtr;
  85.  *
  86.  *    The callInfoPtr struct contains two fields: a client data field and
  87.  *    an interval field.  callInfoPtr->interval is initialized to 0 and
  88.  *    callInfoPtr->clientData is initialized to clientData.  If when func
  89.  *    returns the callInfoPtr->interval is non-zero then the function will
  90.  *    be scheduled to be called again after waiting the given interval.  It
  91.  *    will be passed the client data in callInfoPtr->clientData.
  92.  *
  93.  *    NOTE: There are a fixed number of processes to execute functions 
  94.  *          specified by Proc_CallFunc.  Therefore the functions given
  95.  *          to Proc_CallFunc should always return after a short period
  96.  *          of time.  Otherwise all processes will be tied up.
  97.  *          
  98.  * Results:
  99.  *    None.
  100.  *
  101.  * Side effects:
  102.  *    None.
  103.  *
  104.  *----------------------------------------------------------------------
  105.  */
  106. void
  107. Proc_CallFunc(func, clientData, interval)
  108.     void        (*func) _ARGS_((ClientData clientData, 
  109.             Proc_CallInfo    *callInfoPtr));    /* Function to call. */
  110.     ClientData        clientData;    /* Data to pass function. */
  111.     unsigned    int    interval;    /* Time to wait before calling func. */
  112. {
  113.     FuncInfo    funcInfo;
  114.  
  115.     if (interval != 0) {
  116.     ScheduleFunc(func, clientData, interval, (FuncInfo *) NIL);
  117.     } else {
  118.     funcInfo.func = func;
  119.     funcInfo.data = clientData;
  120.     funcInfo.allocated = FALSE;
  121.     CallFunc(&funcInfo);
  122.     }
  123. }
  124.  
  125. /*
  126.  *----------------------------------------------------------------------
  127.  *
  128.  * Proc_CallFuncAbsTime --
  129.  *
  130.  *    This routine is a variant of Proc_CallFunc. It starts a process
  131.  *    to call the given function at a specific time.  Proc_CallFuncAbsTime 
  132.  *    can not be called with interrupts disabled. When func is called it 
  133.  *    will be called as:
  134.  *
  135.  *        void
  136.  *        func(clientData, callInfoPtr)
  137.  *            ClientData    clientData;
  138.  *            Proc_CallInfo    *callInfoPtr;
  139.  *
  140.  *    The callInfoPtr struct must not be modified!! (it is used by
  141.  *    routines scheduled with Proc_CallFunc).    The only field of interest
  142.  *    is "token" -- it is the same value that was returned by 
  143.  *    Proc_CallFuncAbsTime when func was scheduled. Func will be called 
  144.  *    exactly once: if func needs to be resecheduled, it must call 
  145.  *    Proc_CallFuncAbsTime with a new time value.
  146.  *
  147.  *    NOTE:    There are a fixed number of processes to execute functions 
  148.  *        specified by the Proc_CallFunc* routines.  Therefore the 
  149.  *        functions given to Proc_CallFuncAbsTime should always 
  150.  *        return after a short period of time.  Otherwise all 
  151.  *        processes will be tied up.
  152.  *          
  153.  * Results:
  154.  *    A token to identify this instance of the Proc_CallFuncAbsTime call.
  155.  *    The token is passed to the func in the Proc_CallInfo struct.
  156.  *
  157.  * Side effects:
  158.  *    Memory for the FuncInfo struct is allocated.
  159.  *
  160.  *----------------------------------------------------------------------
  161.  */
  162. ClientData
  163. Proc_CallFuncAbsTime(func, clientData, time)
  164.     void        (*func) _ARGS_((ClientData clientData, 
  165.             Proc_CallInfo    *callInfoPtr));    /* Function to call. */
  166.     ClientData        clientData;    /* Data to pass to func. */
  167.     Timer_Ticks        time;        /* Time when to call func. */
  168. {
  169.     register FuncInfo    *funcInfoPtr;
  170.  
  171.     funcInfoPtr = (FuncInfo *) malloc(sizeof (FuncInfo));
  172.     funcInfoPtr->func = func;
  173.     funcInfoPtr->data = clientData;
  174.     funcInfoPtr->allocated = TRUE;
  175.     funcInfoPtr->queueElement.routine = CallFuncFromTimer;
  176.     funcInfoPtr->queueElement.clientData = (ClientData) funcInfoPtr;
  177.     funcInfoPtr->queueElement.time = time;
  178.     funcInfoPtr->queueElement.interval = 0;
  179.     Timer_ScheduleRoutine(&funcInfoPtr->queueElement, FALSE);
  180.     return((ClientData) funcInfoPtr);
  181. }
  182.  
  183.  
  184. /*
  185.  *----------------------------------------------------------------------
  186.  *
  187.  * Proc_CancelCallFunc --
  188.  *
  189.  *    This routine is used to deschedule a timer entry created by
  190.  *    Proc_CallFuncAbsTime.   
  191.  *          
  192.  * Results:
  193.  *    None.
  194.  *
  195.  * Side effects:
  196.  *    The timer entry is removed from the timer queue.
  197.  *
  198.  *----------------------------------------------------------------------
  199.  */
  200. void
  201. Proc_CancelCallFunc(token)
  202.     ClientData        token;    /* Opaque identifier for function info */
  203. {
  204.     register FuncInfo    *funcInfoPtr = (FuncInfo *) token;
  205.     Boolean removed;
  206.  
  207.     removed = Timer_DescheduleRoutine(&funcInfoPtr->queueElement);
  208.     if (removed && funcInfoPtr->allocated) {
  209.     free((Address) funcInfoPtr);
  210.     }
  211. }
  212.  
  213. /*
  214.  *----------------------------------------------------------------------
  215.  *
  216.  * Proc_ServerInit --
  217.  *
  218.  *    Initialize the state and the set of processes needed to execute
  219.  *    functions.
  220.  *
  221.  * Results:
  222.  *    None.
  223.  *
  224.  * Side effects:
  225.  *    Server info table initialized.
  226.  *
  227.  *----------------------------------------------------------------------
  228.  */
  229. void
  230. Proc_ServerInit()
  231. {
  232.     int        i;
  233.  
  234.     serverInfoTable = 
  235.         (ServerInfo *) Vm_RawAlloc(proc_NumServers * sizeof(ServerInfo));
  236.     for (i = 0; i < proc_NumServers; i++) {
  237.     serverInfoTable[i].index = i;
  238.     serverInfoTable[i].flags = 0;
  239.     serverInfoTable[i].condition.waiting = 0;
  240.     }
  241.     Sync_SemInitDynamic(&serverMutex, "Proc:serverMutex");
  242. }
  243.  
  244.  
  245. /*
  246.  *----------------------------------------------------------------------
  247.  *
  248.  * Proc_ServerProc --
  249.  *
  250.  *    Function for a server process.
  251.  *
  252.  * Results:
  253.  *    None.
  254.  *
  255.  * Side effects:
  256.  *    None.
  257.  *
  258.  *----------------------------------------------------------------------
  259.  */
  260.  
  261. void
  262. Proc_ServerProc()
  263. {
  264.     register    ServerInfo    *serverInfoPtr;
  265.     Proc_CallInfo        callInfo;
  266.     int                i;
  267.     Proc_ControlBlock        *procPtr; /* our process information */
  268.  
  269.     procPtr = Proc_GetCurrentProc();
  270.  
  271.     MASTER_LOCK(&serverMutex);
  272.     Sync_SemRegister(&serverMutex);
  273.     /*
  274.      * Find which server table entry that we are to use.
  275.      */
  276.     for (i = 0, serverInfoPtr = serverInfoTable;
  277.      i < proc_NumServers;
  278.      i++, serverInfoPtr++) {
  279.     if (serverInfoPtr->flags == 0) {
  280.         serverInfoPtr->flags = ENTRY_INUSE;
  281.         break;
  282.     }
  283.     }
  284.     if (i == proc_NumServers) {
  285.     MASTER_UNLOCK(&serverMutex);
  286.     printf("Warning: Proc_ServerProc: No server entries free.\n");
  287.     Proc_Exit(0);
  288.     }
  289.  
  290.     Sched_SetClearUsageFlag();
  291.  
  292.     while (!sys_ShuttingDown) {
  293.     if (!(serverInfoPtr->flags & FUNC_PENDING)) {
  294.         /*
  295.          * There is nothing scheduled for us to do.  If there is something
  296.          * on the queue then dequeue it.  Otherwise sleep.
  297.          */
  298.         if (!QUEUE_EMPTY) {
  299.         serverInfoPtr->info = queue[frontIndex];
  300.         if (frontIndex == NUM_QUEUE_ELEMENTS - 1) {
  301.             frontIndex = 0;
  302.         } else {
  303.             frontIndex++;
  304.         }
  305.         if (frontIndex == nextIndex) {
  306.             frontIndex = -1;
  307.             nextIndex = 0;
  308.         }
  309.         } else {
  310.         Sync_MasterWait(&serverInfoPtr->condition,
  311.                 &serverMutex, TRUE);
  312.         continue;
  313.         }
  314.     }
  315.  
  316.     serverInfoPtr->flags |= SERVER_BUSY;
  317.     serverInfoPtr->flags &= ~FUNC_PENDING;
  318.  
  319.     MASTER_UNLOCK(&serverMutex);
  320.  
  321.     if (procPtr->locksHeld != 0) {
  322.         panic("Proc_ServerProc holding lock before starting function.\n");
  323.     }
  324.  
  325.     /*
  326.      * Call the function.
  327.      */
  328.     callInfo.interval = 0;
  329.     callInfo.clientData = serverInfoPtr->info.data;
  330.     callInfo.token = (ClientData) serverInfoPtr->info.funcInfoPtr;
  331.     serverInfoPtr->info.func(serverInfoPtr->info.data, &callInfo);
  332.  
  333.     if (procPtr->locksHeld != 0) {
  334.         panic("Proc_ServerProc holding lock after calling function.\n");
  335.     }
  336.  
  337.     if (callInfo.interval != 0) {
  338.         /* 
  339.          * It wants us to call it again.
  340.          */
  341.         ScheduleFunc(serverInfoPtr->info.func, callInfo.clientData,
  342.              callInfo.interval, serverInfoPtr->info.funcInfoPtr);
  343.     } else {
  344.         /*
  345.          * Aren't supposed to call it again.  Free up function info
  346.          * if was allocated for this function.
  347.          */
  348.         if (serverInfoPtr->info.funcInfoPtr != (FuncInfo *) NIL) {
  349.         free((Address) serverInfoPtr->info.funcInfoPtr);
  350.         }
  351.     }
  352.  
  353.     /*
  354.      * Go back around looking for something else to do.
  355.      */
  356.     MASTER_LOCK(&serverMutex);
  357.     serverInfoPtr->flags &= ~SERVER_BUSY;
  358.     }
  359.     MASTER_UNLOCK(&serverMutex);
  360.     printf("Proc_ServerProc exiting.\n");
  361. }
  362.  
  363.  
  364. /*
  365.  *----------------------------------------------------------------------
  366.  *
  367.  * ScheduleFunc --
  368.  *
  369.  *    Schedule the given function to be called at the given time.
  370.  *
  371.  * Results:
  372.  *    None.
  373.  *
  374.  * Side effects:
  375.  *    None.
  376.  *
  377.  *----------------------------------------------------------------------
  378.  */
  379.  
  380. static void
  381. ScheduleFunc(func, clientData, interval, funcInfoPtr)
  382.     void        (*func) _ARGS_((ClientData clientData, 
  383.             Proc_CallInfo    *callInfoPtr));    /* Function to call. */
  384.     ClientData        clientData;    /* Data to pass function. */
  385.     unsigned    int    interval;    /* Time to wait before calling func. */
  386.     FuncInfo        *funcInfoPtr;    /* Pointer to function information
  387.                      * structure that may already exist. */
  388. {
  389.     if (funcInfoPtr == (FuncInfo *) NIL) {
  390.     /*
  391.      * We have not allocated a structure yet for waiting.  Do it now.
  392.      */
  393.     funcInfoPtr = (FuncInfo *) malloc(sizeof (FuncInfo));
  394.     funcInfoPtr->func = func;
  395.     funcInfoPtr->data = clientData;
  396.     funcInfoPtr->allocated = TRUE;
  397.     funcInfoPtr->queueElement.routine = CallFuncFromTimer;
  398.     funcInfoPtr->queueElement.clientData = (ClientData) funcInfoPtr;
  399.     } else {
  400.     funcInfoPtr->data = clientData;
  401.     }
  402.  
  403.     /*
  404.      * Schedule the call back.
  405.      */
  406.     funcInfoPtr->queueElement.interval = interval;
  407.     Timer_ScheduleRoutine(&funcInfoPtr->queueElement, TRUE);
  408. }
  409.  
  410.  
  411. /*
  412.  *----------------------------------------------------------------------
  413.  *
  414.  * CallFuncFromTimer --
  415.  *
  416.  *    Actually schedule the calling of the function by one of the
  417.  *    server processes.
  418.  *
  419.  * Results:
  420.  *    None.
  421.  *
  422.  * Side effects:
  423.  *    Item will be enqueued if no free processes are available.  Otherwise
  424.  *    The state of one of the processes is mucked with so that it knows
  425.  *    that it has a function to executed.
  426.  *
  427.  *----------------------------------------------------------------------
  428.  */
  429.  
  430. /* ARGSUSED */
  431. static void
  432. CallFuncFromTimer(time, data)
  433.     Timer_Ticks        time;        /* Unused. */
  434.     ClientData        data;        /* FuncInfo. */
  435. {
  436.     CallFunc((FuncInfo *) data);
  437. }
  438.  
  439.  
  440. /*
  441.  *----------------------------------------------------------------------
  442.  *
  443.  * CallFunc --
  444.  *
  445.  *    Actually schedule the calling of the function by one of the
  446.  *    server processes.
  447.  *
  448.  * Results:
  449.  *    None.
  450.  *
  451.  * Side effects:
  452.  *    Item will be enqueued if no free processes are available.  Otherwise
  453.  *    The state of one of the processes is mucked with so that it knows
  454.  *    that it has a function to executed.
  455.  *
  456.  *----------------------------------------------------------------------
  457.  */
  458.  
  459. static void
  460. CallFunc(funcInfoPtr)
  461.     FuncInfo        *funcInfoPtr;
  462. {
  463.     register    ServerInfo    *serverInfoPtr;
  464.     register    QueueElement    *queueElementPtr;
  465.     Boolean            queueIt = TRUE;
  466.     int                i;
  467.  
  468.     MASTER_LOCK(&serverMutex);
  469.     if (QUEUE_EMPTY) {
  470.     /*
  471.      * If the the queue is empty then there may in fact be a
  472.      * server ready to call out function.
  473.      */
  474.     for (i = 0, serverInfoPtr = serverInfoTable;
  475.          i < proc_NumServers;
  476.          i++, serverInfoPtr++) {
  477.         if (!(serverInfoPtr->flags & ENTRY_INUSE) ||
  478.             (serverInfoPtr->flags & (SERVER_BUSY | FUNC_PENDING))) {
  479.         continue;
  480.         }
  481.         serverInfoPtr->flags |= FUNC_PENDING;
  482.         serverInfoPtr->info.func = funcInfoPtr->func;
  483.         serverInfoPtr->info.data = funcInfoPtr->data;
  484.         if (funcInfoPtr->allocated) {
  485.         serverInfoPtr->info.funcInfoPtr = funcInfoPtr;
  486.         } else {
  487.         serverInfoPtr->info.funcInfoPtr = (FuncInfo *) NIL;
  488.         }
  489.         Sync_MasterBroadcast(&serverInfoPtr->condition);
  490.         queueIt = FALSE;
  491.         break;
  492.     }
  493.     }
  494.  
  495.     if (queueIt) {
  496.     /*
  497.      * There are no free servers available so we have to queue up the
  498.      * message.
  499.      */
  500.     if (QUEUE_FULL) {
  501.         extern Boolean sys_ShouldSyncDisks;
  502.         Mach_EnableIntr();
  503.         sys_ShouldSyncDisks = FALSE;
  504.         panic("CallFunc: Process queue full.\n");
  505.     }
  506.     queueElementPtr = &queue[nextIndex];
  507.     queueElementPtr->func = funcInfoPtr->func;
  508.     queueElementPtr->data = funcInfoPtr->data;
  509.     if (funcInfoPtr->allocated) {
  510.         queueElementPtr->funcInfoPtr = funcInfoPtr;
  511.     } else {
  512.         queueElementPtr->funcInfoPtr = (FuncInfo *) NIL;
  513.     }
  514.     if (nextIndex == NUM_QUEUE_ELEMENTS - 1) {
  515.         nextIndex = 0;
  516.     } else {
  517.         nextIndex++;
  518.     }
  519.     if (frontIndex == -1) {
  520.         frontIndex = 0;
  521.     }
  522.     }
  523.  
  524.     MASTER_UNLOCK(&serverMutex);
  525. }
  526.